/*
* ============================================================================
*  Name        : example_003.cpp
*  Part of     : Finite state machine examples
*  Description : Hello World! 
*  Version     : %version: %
*  
*
* ============================================================================
*/
#include "example_003.h"
#include "example_003.hxx" // State machine source code is here

/**
 * @file example_003.cpp
 *
 * @details
 * More complex state machine. \b 'async', \b 'async_batch' modes. Multiple instances.
 *
 * @ingroup StateMachineExamples
 */
using namespace sea_examples;

// ----------------------------------------------------------------------------
// Hello Word example: Every word is printed in its own state with delay
// ----------------------------------------------------------------------------
void sea_examples::launch_example_003( )
{
    SEA_TRACE_ENTRY( );

    // 1. Instantiate state machine
    // 2. Compile the source code or reuse compiled one
    // 3. Execute state machine. The function will not leave until state machine is finished in 'sync' and 'parser' modes
    // 4. Release local state machine reference as soon as you dont need to communicate to the state machine.
    // 5. Terminate state machine engine at the application exit. It also terminates all unfinished state machines.

    {
        sea::ref< HelloTheWorld_003 > sm;
        sm << NEW HelloTheWorld_003;
        if ( sm->create( 0, HelloTheWorld_003_src ) != eOk ){ /* See Error codes */ }
        if ( sm->start( ) != eOk ){ /* See Error codes */ }
    }
    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above, but start it in anync mode and wait for it to finish
// Adding StateMachine::RunAsync as a parameter to start( ) overrides
// default exec mode specified in the state machine source. See example_003.hxx
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0031( )
{
    SEA_TRACE_ENTRY( );

    {
        sea::ref< HelloTheWorld_003 > sm;
        sm << NEW HelloTheWorld_003;
        if ( sm->create( 0, HelloTheWorld_003_src ) != eOk ){ /* See Error codes */ }
        if ( sm->start( StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

        // Wait on manager that owns the state machine to finish
        sm->wait_manager_to_finish( );
    }

    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above with multiple instances. Exec mode async_batch. 
// Runs all specified state machines in one new thread/sm manager
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0032( )
{
    SEA_TRACE_ENTRY( );

    // Create n instances of the same state machine
    int n = 3;

    vector< StateMachine* > container;
    HelloTheWorld_003* sm;

    // Create and fill the array
    for ( int i = 0; i < n; i++ )
    {
        sm = NEW HelloTheWorld_003;
        if ( sm->create( 0, HelloTheWorld_003_src ) != eOk ){ /* See Error codes */ }
        container.insert( container.end( ), sm );
    }
    
    // Launch all state machines in 'async_batch' mode. 
    if ( StateMachine::start( container, NULL, StateMachine::RunAsyncBatch ) != eOk ){ /* See Error codes */ }

    // Wait for all state machines to finish + the manager
    // because it is common for all batch
    container[ 0 ]->wait_manager_to_finish( );

    // Dispose the references as long as no need for communicating
    // with the state machines
    for ( int i = 0; i < n; i++ )container[ i ]->release_ref( );

    // Terminate the framework, while all state machines are still running
    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above but each state machine runs in its own thread/manager
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0033( )
{
    SEA_TRACE_ENTRY( );

    // Create n instances of the same state machine
    int n = 3;

    vector< StateMachine* > container;
    HelloTheWorld_003* sm;

    // Create and fill the array
    for ( int i = 0; i < n; i++ )
    {
        sm = NEW HelloTheWorld_003;
        if ( sm->create( 0, HelloTheWorld_003_src ) != eOk ){ /* See Error codes */ }
        container.insert( container.end( ), sm );
    }
    
    // Launch all state machines in 'async' mode. 
    if ( StateMachine::start( container, NULL, StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

    // Waiting for all state machines + managers to finish
    container[ 0 ]->wait_manager_to_finish( );
    container[ 1 ]->wait_manager_to_finish( );
    container[ 2 ]->wait_manager_to_finish( );

    // Dispose the references as long as no need for communicating
    // with the state machines
    for ( int i = 0; i < n; i++ )container[ i ]->release_ref( );

    // Terminate the framework, while all state machines are still running
    Engine::terminate( );
}


// ----------------------------------------------------------------------------
// Ctor. Base StateMachine class requires user class name to register in the 
// framework meta system
// ----------------------------------------------------------------------------
HelloTheWorld_003::HelloTheWorld_003( ) : 
    StateMachine( STATEMACHINE_NAME )
{
}

// ----------------------------------------------------------------------------
// Action function. Print 'Hello'
// ----------------------------------------------------------------------------
ACT_IMPL( HelloTheWorld_003, say_hello )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "\n<<<< Hello >>>>\n" ); 
}

// ----------------------------------------------------------------------------
// Action function. Print 'sea'
// ----------------------------------------------------------------------------
ACT_IMPL( HelloTheWorld_003, say_sea )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "\n<<<< SEA >>>>\n" ); 
}

// ----------------------------------------------------------------------------
// Action function. Print 'world'
// ----------------------------------------------------------------------------
ACT_IMPL( HelloTheWorld_003, say_world )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "\n<<<< World! >>>>\n" ); 
}

